package map;

import java.awt.Point;
import java.util.ArrayList;

import map.CellStatus.CellStatusType;


import Model.Car;
import Model.CrossRoads;
import Model.Edge;

public class Utility {
	void generateMap(Map mapClass) {
		Cell[][] map = mapClass.getMap();
		for (int i = 0; i < 5; ++i) {
			for (int j = 0; j < map.length; ++j) {
				if ((0 <= j && j < 3) || (5 <= j && j <= 7)
						|| (10 <= j && j <= 12) || (15 <= j && j <= 17)) {
					if (i == 3)
						map[i][j].setStatus(CellStatusType.LEFT);
					else if (i == 4)
						map[i][j].setStatus(CellStatusType.RIGHT);
					else
						map[i][j].setStatus(CellStatusType.BLOCK);
				} else {
					if ((j == 3 || j == 8 || j == 13) && i < 3) {
						map[i][j].setStatus(CellStatusType.DOWN);
						map[i][j].setOccupied(false);
					} else if ((j == 4 || j == 9 || j == 14) && i < 3) {
						map[i][j].setStatus(CellStatusType.UP);
						map[i][j].setOccupied(false);
					}
				}

			}
		}

		for (int i = 5; i < 10; ++i) {
			for (int j = 0; j < map.length; ++j) {
				if ((0 <= j && j < 3) || (5 <= j && j <= 7)
						|| (10 <= j && j <= 12) || (15 <= j && j <= 17)) {
					if (i == 8)
						map[i][j].setStatus(CellStatusType.LEFT);
					else if (i == 9)
						map[i][j].setStatus(CellStatusType.RIGHT);
					else
						map[i][j].setStatus(CellStatusType.BLOCK);
				} else {
					if ((j == 3 || j == 8 || j == 13) && i < 8) {
						map[i][j].setStatus(CellStatusType.DOWN);
						map[i][j].setOccupied(false);
					} else if ((j == 4 || j == 9 || j == 14) && i < 8) {
						map[i][j].setStatus(CellStatusType.UP);
						map[i][j].setOccupied(false);
					}
				}
			}

		}

		for (int i = 10; i < 15; ++i) {
			for (int j = 0; j < map.length; ++j) {
				if ((0 <= j && j < 3) || (5 <= j && j <= 7)
						|| (10 <= j && j <= 12) || (15 <= j && j <= 17)) {
					if (i == 13)
						map[i][j].setStatus(CellStatusType.LEFT);
					else if (i == 14)
						map[i][j].setStatus(CellStatusType.RIGHT);
					else
						map[i][j].setStatus(CellStatusType.BLOCK);
				} else {
					if ((j == 3 || j == 8 || j == 13) && i < 13) {
						map[i][j].setStatus(CellStatusType.DOWN);
						map[i][j].setOccupied(false);
					} else if ((j == 4 || j == 9 || j == 14) && i < 13) {
						map[i][j].setStatus(CellStatusType.UP);
						map[i][j].setOccupied(false);
					}
				}
			}
		}

		for (int i = 15; i < map.length; ++i) {
			for (int j = 0; j < map.length; ++j) {
				if ((0 <= j && j < 3) || (5 <= j && j <= 7)
						|| (10 <= j && j <= 12) || (15 <= j && j <= 17)) {
					map[i][j].setStatus(CellStatusType.BLOCK);
				} else {
					if ((j == 3 || j == 8 || j == 13) && i < 18) {
						map[i][j].setStatus(CellStatusType.DOWN);
						map[i][j].setOccupied(false);
					} else if ((j == 4 || j == 9 || j == 14) && i < 18) {
						map[i][j].setStatus(CellStatusType.UP);
						map[i][j].setOccupied(false);
					}
				}
			}
		}
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map.length; j++) {
				if(!map[i][j].equals(CellStatusType.CROSS) && !map[i][j].equals(CellStatusType.BLOCK)){
					mapClass.getRandomPos().add(new Point(i, j));
				}
			}
		}
		// MAPPING DEGLI INGRESSI, L'INDICE NELL'ARRAY INDICA L'ID DELL'INGRESSO
		// (COPPIE INGRESSO-USCITA)
		// MAPPING DEGLI INGRESSI, L'INDICE NELL'ARRAY INDICA L'ID DELL'INGRESSO
		// (COPPIE INGRESSO-USCITA)
		//SETTING DELLO STATUS DEGLI INGRESSI E DELLE USCITE
		mapClass.getEntries().add(new Entry(new Point(0, 3), new Point(0, 4)));
		map[0][3].setBorder(true);
		map[0][4].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(0, 8), new Point(0, 9)));
		map[0][8].setBorder(true);
		map[0][9].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(0, 13), new Point(0, 14)));
		map[0][13].setBorder(true);
		map[0][14].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(4, 0), new Point(3, 0)));
		map[4][0].setBorder(true);
		map[3][0].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(9, 0), new Point(8, 0)));
		map[9][0].setBorder(true);
		map[8][0].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(14, 0), new Point(13, 0)));
		map[14][0].setBorder(true);
		map[13][0].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(17, 4), new Point(17, 3)));
		map[17][4].setBorder(true);
		map[17][3].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(17, 9), new Point(17, 8)));
		map[17][9].setBorder(true);
		map[17][8].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(17, 14), new Point(17, 13)));
		map[17][14].setBorder(true);
		map[17][13].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(3, 17), new Point(4, 17)));
		map[3][17].setBorder(true);
		map[4][17].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(8, 17), new Point(9, 17)));
		map[8][17].setBorder(true);
		map[9][17].setBorder(true);
		mapClass.getEntries().add(new Entry(new Point(13, 17), new Point(14, 17)));
		map[13][17].setBorder(true);
		map[14][17].setBorder(true);
		graphCreation(mapClass);

		// CREO L'HASHMAP DELLE LISTE DI ATTESA PER INGRESSO
		mapClass.getWaitLists().put(new Point(0, 3), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(0, 8), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(0, 13), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(4, 0), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(9, 0), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(14, 0), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(17, 4), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(17, 9), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(17, 14), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(3, 17), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(8, 17), new ArrayList<Car>());
		mapClass.getWaitLists().put(new Point(13, 17), new ArrayList<Car>());
	}

	private void graphCreation(Map mapClass) {
		Cell[][] map  = mapClass.getMap();
		int size = map.length;
		// CREAZIONE GRAFO DEGLI INCROCI
		int numCrossRoads = 3;
		CrossRoads[][] matrix = new CrossRoads[numCrossRoads][numCrossRoads];
		for (int i = 0; i < numCrossRoads; i++) 
			for (int j = 0; j < numCrossRoads; j++) 
				matrix[i][j]=null;
		
		int iM = 0;
		int jM = 0;
		for (int i = 0; i < size; ++i) {
			boolean foundCrossRoads = false;
			for (int j = 0; j < size; ++j) {
				if (map[i][j].getStatus().equals(CellStatusType.CROSS)) {
					Point a = new Point(i, j);
					Point b = new Point(i, j + 1);
					Point c = new Point(i + 1, j);
					Point d = new Point(i + 1, j + 1);

					CrossRoads cros = new CrossRoads(a, b, c, d, false);

					// aggiunta nella mappa del punto per avere il nodo del
					// grafo
					mapClass.getMapForGraph().put(a, cros);
					mapClass.getMapForGraph().put(b, cros);
					mapClass.getMapForGraph().put(c, cros);
					mapClass.getMapForGraph().put(d, cros);
					System.out.println(iM + " - " + jM);
					foundCrossRoads = true;
					matrix[iM][jM++] = cros;
					// vado avanti se ne trovo uno
					mapClass.getCrossRoadsGraph().addVertex(cros);
					j++;
				}
			}

			if (foundCrossRoads) {
				jM = 0;
				iM++;
				i++;
			}
			System.out.println();
		}
		
		
		
		for (int i = 0; i < numCrossRoads; i++) {
			for (int j = 0; j < numCrossRoads; j++) {
				if(matrix[i][j]!=null)
				System.out.print(matrix[i][j] + " ");
				else
				System.out.print(" NULL ");
			}
			System.out.println();
		}
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix.length; j++) {
				
				if (i + 1 < matrix.length) {
					CrossRoads n1 = matrix[i][j];
					CrossRoads n2 = matrix[i + 1][j];
					mapClass.getCrossRoadsGraph().addEdge(n1, n2);
					Edge e = mapClass.getCrossRoadsGraph().getEdge(n1, n2);
					e.setPointsList(n1.getcDownExit(),n2.getaDownEntry() , mapClass);
					mapClass.getCrossRoadsGraph().setEdgeWeight(e, 0.0d);
				}
				if (j + 1 < matrix.length) {
					CrossRoads n1 = matrix[i][j];
					CrossRoads n2 = matrix[i][j + 1];
					mapClass.getCrossRoadsGraph().addEdge(n1, n2);
					Edge e = mapClass.getCrossRoadsGraph().getEdge(n1, n2);
					e.setPointsList(n1.getdRightExit(),n2.getcRightEntry() , mapClass);
					mapClass.getCrossRoadsGraph().setEdgeWeight(e, 0.0d);
				}
				if (j - 1 >= 0 ) {
					CrossRoads n1 = matrix[i][j];
					CrossRoads n2 = matrix[i][j - 1];
					mapClass.getCrossRoadsGraph().addEdge(n1, n2);
					Edge e = mapClass.getCrossRoadsGraph().getEdge(n1, n2);
					e.setPointsList(n1.getaLeftExit(),n2.getbLeftEntry() , mapClass);
					mapClass.getCrossRoadsGraph().setEdgeWeight(e, 0.0d);
				}
				if (i - 1 >= 0 ) {
					CrossRoads n1 = matrix[i][j];
					CrossRoads n2 = matrix[i - 1][j];
					mapClass.getCrossRoadsGraph().addEdge(n1, n2);
					Edge e = mapClass.getCrossRoadsGraph().getEdge(n1, n2);
					e.setPointsList(n1.getbUpExit(),n2.getdUpEntry() , mapClass);
					mapClass.getCrossRoadsGraph().setEdgeWeight(e, 0.0d);
				}
			}
		}
		
		
		
		for (Entry entry : mapClass.getEntries()) {
			CrossRoads cross = new CrossRoads(new Point(entry.getCoordEntry().x, entry.getCoordEntry().y),new Point(entry.getCoordExit().x, entry.getCoordExit().y), new Point(), new Point(), true);
			mapClass.getCrossRoadsGraph().addVertex(cross);
			mapClass.getMapForGraph().put(cross.getA(), cross);
			mapClass.getMapForGraph().put(cross.getB(), cross);
			CrossRoads prec = getNextNearestCrossRoads(entry.getCoordEntry(), mapClass);
			
			mapClass.getCrossRoadsGraph().addEdge(cross, prec);
			Edge e = mapClass.getCrossRoadsGraph().getEdge(cross,prec);
			mapClass.getCrossRoadsGraph().setEdgeWeight(e, 0.0);
			System.out.println("entry--------------------");
			if(cross.getA().x == 0){
				e.setPointsList(cross.getA(), prec.getaDownEntry(), mapClass);
			}else if(cross.getA().x == 17){
				e.setPointsList(cross.getA(), prec.getdUpEntry(), mapClass);
			}else if(cross.getA().y == 0){
				e.setPointsList(cross.getA(), prec.getcRightEntry(), mapClass);
			}else if(cross.getA().y == 17){
				e.setPointsList(cross.getA(), prec.getbLeftEntry(), mapClass);
			}
			
			mapClass.getCrossRoadsGraph().addEdge(prec, cross);
			Edge e1 = mapClass.getCrossRoadsGraph().getEdge(prec,cross);
			mapClass.getCrossRoadsGraph().setEdgeWeight(e1, 0.0);
			
			if(cross.getB().x == 0){
				e1.setPointsList(prec.getbUpExit(), cross.getB(), mapClass);
			}else if(cross.getB().x == 17){
				e1.setPointsList(prec.getcDownExit(), cross.getB(), mapClass);
			}else if(cross.getB().y == 0){
				e1.setPointsList(prec.getaLeftExit(), cross.getB(), mapClass);
			}else if(cross.getB().y == 17){
				e1.setPointsList(prec.getdRightExit(), cross.getB(), mapClass);
			}
		}
//		for (Edge edge : crossRoadsGraph.edgeSet()) {
//					System.out.println("ARCO " + crossRoadsGraph.getEdgeSource(edge) + " -> " + crossRoadsGraph.getEdgeTarget(edge));
//				}
	}

	public final CrossRoads getPrecNearestCrossRoads(Point p, Map mapForClass) {
		Cell[][] map = mapForClass.getMap();
		int size = map.length;
		Point mincPointCrossRoads = null;
		int min = 9999999;
		if (map[p.x][p.y].getStatus().equals(CellStatusType.LEFT)) {
			// X+1
			for (int i = p.y; i < p.y + 4 && i < size; i++) {
				if (map[p.x][i].getStatus().equals(CellStatusType.CROSS)) {
					if (min > i - p.y) {
						min = i - p.y;
						mincPointCrossRoads = new Point(p.x, i);
					}
				}

			}
		}

		if (map[p.x][p.y].getStatus().equals(CellStatusType.RIGHT)) {
			// X+1
			for (int i = p.y; i > p.y - 4 && i >= 0; i--) {
				if (map[p.x][i].getStatus().equals(CellStatusType.CROSS)) {
					if (min > p.y - i) {
						min = p.y - i;
						mincPointCrossRoads = new Point(p.x, i);
					}
				}

			}
		}

		if (map[p.x][p.y].getStatus().equals(CellStatusType.UP)) {
			// Y+1
			for (int j = p.x; j < p.x + 4 && j < size; j++) {

				if (map[j][p.y].getStatus().equals(CellStatusType.CROSS)) {
					if (min > j - p.x) {
						min = j - p.x;
						mincPointCrossRoads = new Point(j, p.y);
					}
				}

			}
		}

		if (map[p.x][p.y].getStatus().equals(CellStatusType.DOWN)) {
			// Y+1
			for (int j = p.x; j > p.x - 4 && j >= 0; j--) {

				if (map[j][p.y].getStatus().equals(CellStatusType.CROSS)) {
					if (min > p.x - j) {
						min = p.x - j;
						mincPointCrossRoads = new Point(j, p.y);
					}
				}

			}
		}

		// if (mincPointCrossRoads != null)
		// System.out.println(mincPointCrossRoads + "prec crossroads");
		// else
		// System.out.println("no prec crossroads");
		return mapForClass.getMapForGraph().get(mincPointCrossRoads);

	}

	/*
	 * DATO UN PUNTO TROVA L'INCROCIO PIU' VICINO RITORNA NULL SE NON NE TROVA
	 */
	public final CrossRoads getNextNearestCrossRoads(Point p, Map mapForClass) {
		Cell[][] map = mapForClass.getMap();
		int size = map.length;
		Point mincPointCrossRoads = null;
		int min = 9999999;
		if (map[p.x][p.y].getStatus().equals(CellStatusType.RIGHT)) {
			// X+1
			for (int i = p.y; i < p.y + 4 && i < size; i++) {
				if (map[p.x][i].getStatus().equals(CellStatusType.CROSS)) {
					if (min > i - p.y) {
						min = i - p.y;
						mincPointCrossRoads = new Point(p.x, i);
					}
				}

			}
		}

		if (map[p.x][p.y].getStatus().equals(CellStatusType.LEFT)) {
			// X+1
			for (int i = p.y; i > p.y - 4 && i >= 0; i--) {
				if (map[p.x][i].getStatus().equals(CellStatusType.CROSS)) {
					if (min > p.y - i) {
						min = p.y - i;
						mincPointCrossRoads = new Point(p.x, i);
					}
				}

			}
		}

		if (map[p.x][p.y].getStatus().equals(CellStatusType.DOWN)) {
			// Y+1
			for (int j = p.x; j < p.x + 4 && j < size; j++) {

				if (map[j][p.y].getStatus().equals(CellStatusType.CROSS)) {
					if (min > j - p.x) {
						min = j - p.x;
						mincPointCrossRoads = new Point(j, p.y);
					}
				}

			}
		}

		if (map[p.x][p.y].getStatus().equals(CellStatusType.UP)) {
			// Y+1
			for (int j = p.x; j > p.x - 4 && j >= 0; j--) {

				if (map[j][p.y].getStatus().equals(CellStatusType.CROSS)) {
					if (min > p.x - j) {
						min = p.x - j;
						mincPointCrossRoads = new Point(j, p.y);
					}
				}

			}
		}

		// if (mincPointCrossRoads != null)
		// System.out.println(mincPointCrossRoads + "next crossroads");
		// else
		// System.out.println("no next crossroads");
		return mapForClass.getMapForGraph().get(mincPointCrossRoads);

	}
}
